#include "bsp_flash.h"
#include "main.h"
#include "string.h"

static uint32_t get_sector(uint32_t address);

/**
 * @brief:      BSP_Flash_Write
 * @details:    向flash中的一个位置更新数据，支持增量更新
 * @param[in]  address: Flash起始地址
 * @param[in]  data: 要写入的数据指针
 * @param[in]  len: 数据长度（uint16_t的个数）
 * @retval     成功返回1，失败返回0
 */
uint8_t BSP_Flash_Update(uint32_t address, uint16_t* data, uint16_t len)
{
  // 参数检查
  if (data == NULL || len == 0 || len > FLASH_OFFSETS_COUNT) {
    return 0;
  }
  // 检查地址是否在有效范围内
  if (address < ADDR_FLASH_SECTOR_0 || address >= FLASH_END_ADDR) {
    return 0;
  }
  
  // 读取当前Flash中的数据
  uint16_t current_data[FLASH_OFFSETS_COUNT];
  flash_read(address, (uint32_t*)current_data, (FLASH_OFFSETS_LENGTH + 3) / 4);
  
  // 检查是否需要更新（比较数据是否发生变化）
  uint8_t need_update = 0;
  for (int i = 0; i < len; i++) {
    if (current_data[i] != data[i]) {
      need_update = 1;
      break;
    }
  } 
  // 如果数据没有变化，直接返回成功
  if (!need_update) {
    return 1;
  }
  
  // 准备完整的数据缓冲区（包含未修改的部分）
  uint16_t write_data[FLASH_OFFSETS_COUNT];
  // 复制原有数据
  for (int i = 0; i < FLASH_OFFSETS_COUNT; i++) {
    write_data[i] = current_data[i];
  }
  
  // 更新需要修改的数据
  for (int i = 0; i < len; i++) {
      write_data[i] = data[i];
  }
  
  // Flash操作
  HAL_FLASH_Unlock();
  // 擦除整个sector
  flash_erase_address(address, 1);
  // 写入新数据
  int8_t result = flash_write_single_address(address, (uint32_t*)write_data, 
                                            (FLASH_OFFSETS_LENGTH + 3) / 4);
  HAL_FLASH_Lock();
  return result == -1 ? 0 : 1;
}

/**
 * @brief:      BSP_Flash_Read
 * @details:    从flash中读取数据
 * @param[in]  address: Flash起始地址
 * @param[out] data: 存储读取数据的缓冲区
 * @param[in]  len: 要读取的数据长度
 */
void BSP_Flash_Read(uint32_t address, uint16_t* data, uint16_t len)
{
  if (data == NULL || len == 0 || len > FLASH_OFFSETS_COUNT) {
    return;
  }
  
  uint16_t temp_data[FLASH_OFFSETS_COUNT];
  flash_read(address, (uint32_t*)temp_data, (FLASH_OFFSETS_LENGTH + 3) / 4);
  
  for (int i = 0; i < len; i++) {
    data[i] = temp_data[i];
  }
}

/**
 * @brief:      BSP_Flash_Init
 * @details:    初始化Flash数据，如果第一次使用则写入默认值
 * @param[in]  default_data: 默认数据
 */
void BSP_Flash_Init(uint16_t* read_data, uint16_t* default_data)
{
  // uint16_t read_data[FLASH_OFFSETS_COUNT];
  BSP_Flash_Read(FLASH_OFFSETS_ADDRESS, read_data, FLASH_OFFSETS_COUNT);
  
  // 检查是否为初始状态（全0xFF）
  uint8_t is_initialized = 0;
  for (int i = 0; i < FLASH_OFFSETS_COUNT; i++) {
    if (read_data[i] != 0xFFFF) {
      is_initialized = 1;
      break;
    }
  }
  
  // 如果是初始状态，写入默认值
  if (!is_initialized && default_data != NULL) {
    BSP_Flash_Update(FLASH_OFFSETS_ADDRESS, default_data, FLASH_OFFSETS_COUNT);
  }
}



/**
  * @brief          擦除flash
  * @param[in]      address: flash 地址
  * @param[in]      len: 页数量
  * @retval         none
  */
void flash_erase_address(uint32_t address, uint16_t len)
{
  FLASH_EraseInitTypeDef flash_erase;
  uint32_t error;

  flash_erase.Sector = get_sector(address);
  flash_erase.TypeErase = FLASH_TYPEERASE_SECTORS;
  flash_erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;
  flash_erase.NbSectors = len;

  HAL_FLASH_Unlock();
  HAL_FLASHEx_Erase(&flash_erase, &error);
  HAL_FLASH_Lock();
}

/**
  * @brief          往一页flash写数据
  * @param[in]      start_address: flash 地址
  * @param[in]      buf: 数据指针
  * @param[in]      len: 数据长度
  * @retval         success 0, fail -1
  */
int8_t flash_write_single_address(uint32_t start_address, uint32_t *buf, uint32_t len)
{
  static uint32_t uw_address;
  static uint32_t end_address;
  static uint32_t *data_buf;
  static uint32_t data_len;

  HAL_FLASH_Unlock();

  uw_address = start_address;
  end_address = get_next_flash_address(start_address);
  data_buf = buf;
  data_len = 0;

  while (uw_address <= end_address)
  {
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,uw_address, *data_buf) == HAL_OK)
    {
      uw_address += 4;
      data_buf++;
      data_len++;
      if (data_len == len)
      {
        break;
      }
    }
    else
    {
      HAL_FLASH_Lock();
      return -1;
    }
  }

  HAL_FLASH_Lock();
  return 0;
}

/**
  * @brief          往几页flash写数据
  * @param[in]      start_address: flash 开始地址
  * @param[in]      end_address: flash 结束地址
  * @param[in]      buf: 数据指针
  * @param[in]      len: 数据长度
  * @retval         success 0, fail -1
  */
int8_t flash_write_muli_address(uint32_t start_address, uint32_t end_address, uint32_t *buf, uint32_t len)
{
  uint32_t uw_address = 0;
  uint32_t *data_buf;
  uint32_t data_len;

  HAL_FLASH_Unlock();

  uw_address = start_address;
  data_buf = buf;
  data_len = 0;
  while (uw_address <= end_address)
  {
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,uw_address, *data_buf) == HAL_OK)
    {
      uw_address += 4;
      data_buf++;
      data_len++;
      if (data_len == len)
      {
        break;
      }
    }
    else
    {
      HAL_FLASH_Lock();
      return -1;
    }
  }

  HAL_FLASH_Lock(); 
  return 0;
}

/**
  * @brief          从flash读数据
  * @param[in]      start_address: flash 地址
  * @param[out]     buf: 数据指针
  * @param[in]      len: 数据长度
  * @retval         none
  */
void flash_read(uint32_t address, uint32_t *buf, uint32_t len)
{
  memcpy(buf, (void*)address, len *4);
}

/**
  * @brief          获取flash的sector号
  * @param[in]      address: flash 地址
  * @retval         sector号
  */
uint32_t get_sector(uint32_t address)
{
  uint32_t sector = 0;
  if ((address < ADDR_FLASH_SECTOR_1) && (address >= ADDR_FLASH_SECTOR_0))
  {
    sector = FLASH_SECTOR_0;
  }
  else if ((address < ADDR_FLASH_SECTOR_2) && (address >= ADDR_FLASH_SECTOR_1))
  {
    sector = FLASH_SECTOR_1;
  }
  else if ((address < ADDR_FLASH_SECTOR_3) && (address >= ADDR_FLASH_SECTOR_2))
  {
    sector = FLASH_SECTOR_2;
  }
  else if ((address < ADDR_FLASH_SECTOR_4) && (address >= ADDR_FLASH_SECTOR_3))
  {
    sector = FLASH_SECTOR_3;
  }
  else if ((address < ADDR_FLASH_SECTOR_5) && (address >= ADDR_FLASH_SECTOR_4))
  {
    sector = FLASH_SECTOR_4;
  }
  else if ((address < ADDR_FLASH_SECTOR_6) && (address >= ADDR_FLASH_SECTOR_5))
  {
    sector = FLASH_SECTOR_5;
  }
  else if ((address < ADDR_FLASH_SECTOR_7) && (address >= ADDR_FLASH_SECTOR_6))
  {
    sector = FLASH_SECTOR_6;
  }
  else if ((address < ADDR_FLASH_SECTOR_8) && (address >= ADDR_FLASH_SECTOR_7))
  {
    sector = FLASH_SECTOR_7;
  }
  else if ((address < ADDR_FLASH_SECTOR_9) && (address >= ADDR_FLASH_SECTOR_8))
  {
    sector = FLASH_SECTOR_8;
  }
  else if ((address < ADDR_FLASH_SECTOR_10) && (address >= ADDR_FLASH_SECTOR_9))
  {
    sector = FLASH_SECTOR_9;
  }
  else if ((address < ADDR_FLASH_SECTOR_11) && (address >= ADDR_FLASH_SECTOR_10))
  {
    sector = FLASH_SECTOR_10;
  }
  else if ((address < ADDR_FLASH_SECTOR_12) && (address >= ADDR_FLASH_SECTOR_11))
  {
    sector = FLASH_SECTOR_11;
  }
  else
  {
    sector = FLASH_SECTOR_11;
  }

  return sector;
}

/**
  * @brief          获取下一页flash地址
  * @param[in]      address: flash 地址
  * @retval         下一页flash地址
  */
uint32_t get_next_flash_address(uint32_t address)
{
  uint32_t sector = 0;

  if ((address < ADDR_FLASH_SECTOR_1) && (address >= ADDR_FLASH_SECTOR_0))
  {
    sector = ADDR_FLASH_SECTOR_1;
  }
  else if ((address < ADDR_FLASH_SECTOR_2) && (address >= ADDR_FLASH_SECTOR_1))
  {
    sector = ADDR_FLASH_SECTOR_2;
  }
  else if ((address < ADDR_FLASH_SECTOR_3) && (address >= ADDR_FLASH_SECTOR_2))
  {
    sector = ADDR_FLASH_SECTOR_3;
  }
  else if ((address < ADDR_FLASH_SECTOR_4) && (address >= ADDR_FLASH_SECTOR_3))
  {
    sector = ADDR_FLASH_SECTOR_4;
  }
  else if ((address < ADDR_FLASH_SECTOR_5) && (address >= ADDR_FLASH_SECTOR_4))
  {
    sector = ADDR_FLASH_SECTOR_5;
  }
  else if ((address < ADDR_FLASH_SECTOR_6) && (address >= ADDR_FLASH_SECTOR_5))
  {
    sector = ADDR_FLASH_SECTOR_6;
  }
  else if ((address < ADDR_FLASH_SECTOR_7) && (address >= ADDR_FLASH_SECTOR_6))
  {
    sector = ADDR_FLASH_SECTOR_7;
  }
  else if ((address < ADDR_FLASH_SECTOR_8) && (address >= ADDR_FLASH_SECTOR_7))
  {
    sector = ADDR_FLASH_SECTOR_8;
  }
  else if ((address < ADDR_FLASH_SECTOR_9) && (address >= ADDR_FLASH_SECTOR_8))
  {
    sector = ADDR_FLASH_SECTOR_9;
  }
  else if ((address < ADDR_FLASH_SECTOR_10) && (address >= ADDR_FLASH_SECTOR_9))
  {
    sector = ADDR_FLASH_SECTOR_10;
  }
  else if ((address < ADDR_FLASH_SECTOR_11) && (address >= ADDR_FLASH_SECTOR_10))
  {
    sector = ADDR_FLASH_SECTOR_11;
  }
  else /*(address < FLASH_END_ADDR) && (address >= ADDR_FLASH_SECTOR_23))*/
  {
    sector = FLASH_END_ADDR;
  }
  return sector;
}
